#define GLFW_INCLUDE_NONE
#include "pch.h"
#include "Application.h"
#include "Common.h"
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include "Buffer.h"
#include "GLVertexArray.h"
#include "Renderer.h"
#include "GLShader.h"
#include "Application.h"
namespace HS {

	Application* Application::s_Instance = nullptr;

	
	Application::Application(const std::string& name,int width,int height)
	{
		Log::Init();
		if (s_Instance == nullptr) {
			LOGINFO("Init Application!");
		}
		s_Instance = this;
		m_Window = std::unique_ptr<Window>(Window::Create());
		m_Window->SetEventCallback(BIND_EVENT_FN(Application::OnEvent));
		m_Window->SetVSync(false);
		Render::Init();
		m_ImGuiLayer = new ImGuiLayer();
		PushOverlay(m_ImGuiLayer);
	}

	Application::~Application()
	{
		
	}

	void Application::PushLayer(Layer* layer)
	{
		m_LayerStack.PushLayer(layer);
	}

	void Application::PushOverlay(Layer* layer)
	{
		m_LayerStack.PushOverlay(layer);
	}

	void Application::Close()
	{
		m_Running = false;
	}

	void Application::OnEvent(Event& e)
	{
		EventDispatcher dispatcher(e);
		dispatcher.Dispatch<WindowCloseEvent>(BIND_EVENT_FN(Application::OnWindowClose));
		dispatcher.Dispatch<WindowResizeEvent>(BIND_EVENT_FN(Application::OnWindowResize));
		dispatcher.Dispatch<KeyPressedEvent>(BIND_EVENT_FN(Application::OnKeyPressedEvent));
		m_ImGuiLayer->OnEvent(e);
		for (auto it = m_LayerStack.rbegin(); it != m_LayerStack.rend(); ++it)
		{
			if (e.Handled)
				break;
			(*it)->OnEvent(e);
		}
	}

	void Application::Run()
	{
		while (m_Running)
		{
			float time = (float)glfwGetTime();
			timestep = time - m_LastFrameTime;
			m_LastFrameTime = time;

			if (!m_Minimized)
			{
				for (Layer* layer : m_LayerStack) 
				{
					layer->OnUpdate(timestep);
				}
				
				m_ImGuiLayer->Begin();
				{
					for (Layer* layer : m_LayerStack) 
					{
						layer->OnImGuiRender();
					}
				}
				m_ImGuiLayer->End();
			}

			//Update
			m_Window->OnUpdate();
		}
	}

	bool Application::OnWindowClose(WindowCloseEvent& e)
	{
		m_Running = false;
		return true;
	}

	bool Application::OnWindowResize(WindowResizeEvent& e)
	{
		

		if (e.GetWidth() == 0 || e.GetHeight() == 0)
		{
			m_Minimized = true;
			return false;
		}

		m_Minimized = false;
		Render::OnWindowResize(e.GetWidth(), e.GetHeight());

		return false;
	}

	bool Application::OnKeyPressedEvent(KeyPressedEvent& e)
	{
		if (e.GetKeyCode() == Key::Left)
		{
			m_CamPos.x -= m_CameraSpeed * timestep;
		}
		if (e.GetKeyCode() == Key::Right)
		{
			m_CamPos.x += m_CameraSpeed * timestep;
		}
		if (e.GetKeyCode() == Key::Up)
		{
			m_CamPos.y += m_CameraSpeed * timestep;
		}
		if (e.GetKeyCode() == Key::Down)
		{
			m_CamPos.y -= m_CameraSpeed * timestep;
		}
		if (e.GetKeyCode() == Key::Escape)
		{
			m_Running = false;
		}
		return false;
	}

}
